/********************************************************************************
* @file    app_led.c
* @author  jianqiang.xue
* @version V1.0.0
* @date    2021-04-20
* @brief   LED灯光效果
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <stdio.h>
#include <stdbool.h>
#include <string.h>

#include "app_led.h"
#include "log.h"
#include "os_api.h"
#include "queue.h"
/* Private Includes ----------------------------------------------------------*/
#include "ls_gpio.h"
#include "ls_syscfg.h"

#if LS_APP_LED_PWM_DRIVEN_MODE == 1
#include "bsp_pwm.h"
#endif
#if LS_APP_LED_GPIO_DRIVEN_MODE == 1
#include "bsp_led.h"
#endif
#if LS_APP_LED_WS2812_DRIVEN_MODE == 1
#include "onewire.h"
#endif
/* Private Define ------------------------------------------------------------*/
/* Private Macro -------------------------------------------------------------*/
void app_led(void const *argument);

/* Private Typedef -----------------------------------------------------------*/
#if LS_APP_LED_PWM_DRIVEN_MODE
extern void led_pwm_init(void);
extern bool app_led_pwm_ioctl(app_led_id_t led_id, app_led_type_t type, uint16_t cycle_time,
                       uint32_t period, uint16_t crest_time, uint16_t trough_time);
#endif
#if LS_APP_LED_GPIO_DRIVEN_MODE
extern void led_gpio_init(void);
extern bool app_led_gpio_ioctl(app_led_id_t led_id, app_led_type_t type, uint16_t cycle_time, uint32_t period);
#endif
#if LS_APP_LED_WS2812_DRIVEN_MODE
extern void led_ws2812_init(void);
extern bool app_led_ws2812_ioctl(app_led_id_t led_id, app_led_type_t type, uint16_t cycle_time, uint32_t period);
#endif

// 定义邮箱，用于发送灯光命令
typedef struct
{
    led_driven_t   led_driven;
    app_led_type_t type;                 // 0--灭灯  1--常亮  2--呼吸  3--快闪
    app_led_id_t   led_id;               // 组号
    uint32_t       period;               // 重装载值(控制值) 灯光亮度
    uint16_t       cycle_time;           // 定时器轮询时间ms(灭灯和常亮只执行一次) 可以控制闪烁快慢，呼吸快慢
    uint16_t       crest_time;           // 波峰：最高亮度保持时间ms
    uint16_t       trough_time;          // 波谷：最低亮度保持时间ms
} led_msgqueue_t;

#define RECV_Q_ITEM_CNT                             (LS_APP_LED_FIFO_NUM)
#define RECV_Q_ITEM_SIZE                            (sizeof(led_msgqueue_t))
// 消息队列总缓存区
static uint8_t m_recv_q_buff[RECV_Q_ITEM_CNT * RECV_Q_ITEM_SIZE] = {0};
// 定义队列消息结构体
queue_t m_recv_q =
{
    .pbuff     = m_recv_q_buff,
    .front     = 0,
    .rear      = 0,
    .item_cnt  = RECV_Q_ITEM_CNT,
    .item_size = RECV_Q_ITEM_SIZE
};

/* Public Function Prototypes -----------------------------------------------*/
/****************************[灯光操作]对外接口函数*****************************/
/**
 * @brief  灯光通知函数，创建一个结构体，存放信息，然后发送给消息队列
 * @note   通过消息队列，实现多灯光操作(避免中断嵌套频繁操作硬件)
 * @param  led_driven: 灯光外设类型  [LED_DRIVEN_GPIO], [LED_DRIVEN_PWM], [LED_DRIVEN_WS2812]
 * @param  led_id: 灯光组号
 * @param  type: 灯光类型
 * @param  cycle_time: 周期刷新时间 <-- 决定灯效变化速率，如灯光闪烁快慢
 * @param  period: 最大周期<--决定PWM值
 * @param  crest_time: 波峰：最高亮度保持时间ms
 * @param  trough_time: 波谷：最低亮度保持时间ms
 * @retval 0--失败  1--成功
 */
bool app_led_indicate(led_driven_t led_driven, app_led_id_t led_id, app_led_type_t type, uint16_t cycle_time,
                      uint32_t period, uint16_t crest_time, uint16_t trough_time)
{
    led_msgqueue_t pmsg;
    pmsg.led_driven = led_driven;
    pmsg.led_id     = led_id;
    pmsg.type       = type;
    pmsg.cycle_time = cycle_time;
    pmsg.period     = period;
    pmsg.crest_time = crest_time;
    pmsg.trough_time = trough_time;
    return queue_en(&m_recv_q, (uint8_t *)&pmsg, sizeof(led_msgqueue_t));
}

/**
  * @brief  线程任务：LED操作
  */
bool app_task_led(void)
{
    // 消息队列项目临时缓存区
    uint8_t g_recv_data[RECV_Q_ITEM_SIZE] = {0};
    if (!queue_de(&m_recv_q, g_recv_data))
        return false;
    led_msgqueue_t *pmsg = (led_msgqueue_t *)g_recv_data;

    if (pmsg->led_driven == LED_DRIVEN_GPIO)
    {
#if LS_APP_LED_GPIO_DRIVEN_MODE
        app_led_gpio_ioctl(pmsg->led_id, pmsg->type, pmsg->cycle_time, pmsg->period);
#endif
    }
    else if (pmsg->led_driven == LED_DRIVEN_PWM)
    {
#if LS_APP_LED_PWM_DRIVEN_MODE
        app_led_pwm_ioctl(pmsg->led_id, pmsg->type, pmsg->cycle_time, pmsg->period, pmsg->crest_time, pmsg->trough_time);
#endif
    }
    else if (pmsg->led_driven == LED_DRIVEN_WS2812)
    {
#if LS_APP_LED_WS2812_DRIVEN_MODE
        app_led_ws2812_ioctl(pmsg->led_id, pmsg->type, pmsg->cycle_time, pmsg->period);
        //LOG_D("ws2812[0x%06x][0x%06x]\r\n", pmsg->type, pmsg->period);
#endif
    }
    return true;
}

/**
  * @brief  灯光功能初始化
  */
bool app_led_init(void)
{
#if LS_APP_LED_PWM_DRIVEN_MODE
    // [app] 软定时器创建和参数填充
    led_pwm_init();
    // 外设tim初始化
    bsp_pwm_init();
#endif
#if LS_APP_LED_GPIO_DRIVEN_MODE
    // gpio初始化
    bsp_led_init();
    // [app] 软定时器创建和参数填充
    led_gpio_init();
#endif
#if LS_APP_LED_WS2812_DRIVEN_MODE
    onewire_init();
    led_ws2812_init();
#endif
    return true;
}
